package com.kdgc.energy.dmm.query;

import com.kdgc.energy.dmm.Environment;
import com.kdgc.energy.dmm.lambda.SerializedFunction;
import com.kdgc.energy.dmm.table.Table;
import lombok.Getter;
import org.apache.metamodel.query.FromItem;
import org.apache.metamodel.query.SelectItem;
import org.apache.metamodel.schema.Column;
import org.apache.metamodel.schema.MutableRelationship;
import org.apache.metamodel.schema.Relationship;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xu.wenchang
 * @version 1.0 2022/04/16
 */
public class From {
    @Getter
    private FromItem delegate;
    
    public From(Class<?> clazz) {
        this.delegate = new FromItem(Environment.get(clazz)
                                                .getTable());
    }
    
    public From(Table table) {
        this.delegate = new FromItem(table.getTable());
    }
    
    public From(Query subQuery) {
        this.delegate = new FromItem(subQuery.getQuery());
    }
    
    public void setAlias(String alias) {
        this.delegate.setAlias(alias);
    }
    
    @SafeVarargs
    public static <T, R> From innerJoin(SerializedFunction<T, R>... columns) {
        assert null != columns && columns.length > 1;
        return new From(JoinType.INNER, columns[0], columns[1]);
    }
    
    public <T, R> From(JoinType joinType, SerializedFunction<T, R> leftColumn, SerializedFunction<T, R> rightColumn) {
        List<Column> leftColumnList = Collections.singletonList(Environment.get(leftColumn));
        List<Column> rightColumnList = Collections.singletonList(Environment.get(rightColumn));
        Relationship relationship = MutableRelationship.createRelationship(leftColumnList, rightColumnList);
        this.delegate = new FromItem(JoinTypes.toMetaModelJoinType(joinType), relationship);
    }
    
    public <T, R> From(JoinType joinType, List<SerializedFunction<T, R>> leftColumns, List<SerializedFunction<T, R>> rightColumns) {
        List<Column> leftColumnList = leftColumns.stream()
                                                 .map(Environment::get)
                                                 .collect(Collectors.toList());
        List<Column> rightColumnList = rightColumns.stream()
                                                   .map(Environment::get)
                                                   .collect(Collectors.toList());
        Relationship relationship = MutableRelationship.createRelationship(leftColumnList, rightColumnList);
        this.delegate = new FromItem(JoinTypes.toMetaModelJoinType(joinType), relationship);
    }
    
    public From(JoinType joinType, From leftSide, From rightSide, Select[] leftOn, Select[] rightOn) {
        SelectItem[] leftArr = Arrays.stream(leftOn)
                                     .map(Select::getDelegate)
                                     .toArray(SelectItem[]::new);
        SelectItem[] rightArr = Arrays.stream(rightOn)
                                      .map(Select::getDelegate)
                                      .toArray(SelectItem[]::new);
        this.delegate = new FromItem(JoinTypes.toMetaModelJoinType(joinType), leftSide.delegate, rightSide.delegate, leftArr, rightArr);
    }
}
